﻿#include "Config.h"
//#include "Tool/Macros.h"
#include "rapidjson/error/en.h"
//#include "IO/IO.h"
#include "Parallel/ParallelMPI.h"
#include "Time/SimulationTime.h"
#include "nlohmann/json.hpp"

#include <cmath>
#include <algorithm>
#include <fstream>
#include <iostream>

using namespace std;


//=================global variables: define===============================
const double smallValue = 1.0e-5;
const double verySmallValue = 1.0e-100;
const double largeValue = 1.0e5;
const double veryLargeValue = 1.0e100;

//length***Value is set in Mesh.cpp
double lengthSmallValue;
double lengthVerySmallValue;
double lengthLargeValue;
double lengthVeryLargeValue;
//=================global variables===============================




//---------------------------------------------------------------------------------------------------------------------
//Config : open & parse the input data file, test that parameters are coherent
//---------------------------------------------------------------------------------------------------------------------
Config::Config(ParallelMPI* pmpiIn) :
    pmpi(pmpiIn),
    const_c(299792458.0),
    const_e(1.6021766208e-19),
    const_emass(9.10938356e-31),
    const_ephi0(8.854187817620389e-12),
    const_ephi0_inv(1.0/8.854187817620389e-12),
    const_pi(3.1415926),
    const_boltz(1.3806e-23),
    const_h(6.62606957e-34),
    const_unitAtomMass(1.6605390666e-27)
{
    //================== read and parse parameter.inp file of json format ======================
    std::ifstream in(file_name);
    if(!in.is_open())
    {
        log_error<<"fail to read input file: data/easypic3d.json";
    }

    //nlohmann
    /*
    nlohmann::json j;
    in >> j;

    double mes = j["externB"][1];
    std::vector<double> mesVector = j["externB"].get<std::vector<double>>();

    cout<<"nlohmann "<<mes<<endl;
    */


    std::string json_content((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
    in.close();

    if(dom.Parse(json_content.c_str()).HasParseError())
    {
         log_error<<"params dom error at offset " << dom.GetErrorOffset() << ": " << GetParseError_En(dom.GetParseError());
    }



    //================== read parameters ======================

    if (!get_int(dimension, "dimension"))
    {
        dimension = 3;
    }

    if (!get_string(electromagneticFieldType, "electromagneticFieldType"))
    {
        log_warning << "no electromagneticFieldType, set default value: electrostatic";
        electromagneticFieldType = "electrostatic";
    }

    if (!get_bool(isCylindricalCoordinateSystem, "isCylindricalCoordinateSystem"))
    {
        isCylindricalCoordinateSystem = false;
    }

    if (!get_int(order, "order"))
    {
        order = 1;
    }

    
    if(!get_bool(isBarycentricCoordinateParticleTracking, "isBarycentricCoordinateParticleTracking"))
    {
        isBarycentricCoordinateParticleTracking = true;
    }


    if(!get_bool(isWriteAllProcess, "isWriteAllProcess"))
    {
        isWriteAllProcess = false;
    }


    if (!get_bool(isWriteVtk, "isWriteVtk"))
    {
        isWriteVtk = false;
    }

    if (!get_string(dataBaseDir, "dataBaseDir"))
    {
        log_warning << "database path must be set";
        exit(0);
    }

    if (!get_int(debugLevel, "debugLevel"))
    {
        debugLevel = 1;
    }

    if (!get_bool(isChargeInDielectricMove, "isChargeInDielectricMove"))
    {
        isChargeInDielectricMove = false;
    }

    if (!get_double(zDirectionLength, "zDirectionLength"))
    {
        zDirectionLength = 1.0;
    }

    //log_info << "reading mesh";
    readMeshParameter();

    //log_info << "reading mesh";
    readElectroMagneticFieldParameter();

    readElectroMagneticFieldDGTDparameter();

    //log_info << "reading species";
    read_species();

    //log_info << "reading particle source";
    read_particle_source();

    //log_info << "reading simulation time";
    read_simulation_time();

    //log_info << "reading collision";
    read_collision();

    //log_info << "reading psi";
    read_psi();

    //log_info << "reading material database";
    readMaterialDatabase();

    readRecord();

    readLicense();

}

void Config::read_species()
{
    if(dom.HasMember("Species") && dom["Species"].IsArray())
    {
        const rapidjson::Value& arr = dom["Species"];
        species_param.resize(arr.Size());
        for(int i = 0; i < arr.Size(); ++i)
        {
            const rapidjson::Value& tmp = arr[i];

            if(!get_class_string(tmp, species_param[i].species_name, "species_name"))
            {

            }

            species_param[i].species_number = i;

            if(!get_class_string(tmp, species_param[i].species_type, "species_type"))
            {

            }

            if(!get_class_string(tmp, species_param[i].move_type, "move_type"))
            {
                species_param[i].move_type = "em";
            }
            
            if(!get_class_string(tmp, species_param[i].init_position_type, "init_position_type"))
            {

            }

            if(!get_class_string(tmp, species_param[i].init_velocity_type, "init_velocity_type"))
            {

            }

            if(!get_class_double(tmp, species_param[i].c_part_max, "c_part_max"))
            {

            }

            if(!get_class_double(tmp, species_param[i].mass, "mass"))
            {
                log_error << "species no mass: " << species_param[i].species_name;
            }
            species_param[i].mass *= const_unitAtomMass;

            if(!get_class_double(tmp, species_param[i].charge, "charge"))
            {
                int charge;
                if (!get_class_int(tmp, charge, "charge"))
                {

                    log_error << "species no charge: " << species_param[i].species_name;
                }
                else
                {
                    species_param[i].charge = charge;
                }
            }
            species_param[i].charge *= const_e;

            if(!get_class_double(tmp, species_param[i].number_density, "number_density"))
            {
                species_param[i].number_density = 0.0;
            }

            if (!get_class_string(tmp, species_param[i].numberDensityString, "numberDensityString"))
            {
                species_param[i].numberDensityString = "";
            }

            if(!get_class_int(tmp, species_param[i].n_part_per_cell, "n_part_per_cell"))
            {
                species_param[i].n_part_per_cell = 0;
            }

            if(!get_class_int(tmp, species_param[i].maxMacroParticleNumberPerCell, "maxMacroParticleNumberPerCell"))
            {
                species_param[i].maxMacroParticleNumberPerCell = 1000;
            }

            if (!get_class_int(tmp, species_param[i].maxMaxMacroParticleNumberPerCell, "maxMaxMacroParticleNumberPerCell"))
            {
                species_param[i].maxMaxMacroParticleNumberPerCell = species_param[i].maxMacroParticleNumberPerCell * 5;
            }

            if(!get_class_string(tmp, species_param[i].combineCriterion, "combineCriterion"))
            {
                species_param[i].combineCriterion = "maxWeight";
                //combineCriterion = "maxPhysicalParticleNumber";
            }

            if (!get_class_string(tmp, species_param[i].combineAlgorithm, "combineAlgorithm"))
            {
                //species_param[i].combineAlgorithm = "velocityOrder";
                //species_param[i].combineAlgorithm = "weightOrder";
                species_param[i].combineAlgorithm = "randomOrder";
            }
            log_info << "combineAlgorithm: " << species_param[i].combineAlgorithm;

            if(!get_class_double(tmp, species_param[i].combineMaxWeight, "combineMaxWeight"))
            {
                species_param[i].combineMaxWeight = 1.0e99;
            }

            if(!get_class_double(tmp, species_param[i].combineMaxPhysicalParticleNumber, "combineMaxPhysicalParticleNumber"))
            {
                species_param[i].combineMaxPhysicalParticleNumber = 1.0e99;
            }

            if(!get_class_int(tmp, species_param[i].combineMaxMacroParticleNumberPerCell, "combineMaxMacroParticleNumberPerCell"))
            {
                species_param[i].combineMaxMacroParticleNumberPerCell = 1000;
            }


            if(!get_class_double(tmp, species_param[i].temperature, "temperature"))
            {
                species_param[i].temperature = 0.0;
            }

            if(!get_class_double(tmp, species_param[i].temperature_x, "temperature_x"))
            {
                species_param[i].temperature_x = 0.0;
            }
            //log_info<<"temperature_x: "<<species_param[i].temperature_x;

            if(!get_class_double(tmp, species_param[i].temperature_y, "temperature_y"))
            {
                species_param[i].temperature_y = 0.0;
            }
            //log_info<<"temperature_y: "<<species_param[i].temperature_y;

            if(!get_class_double(tmp, species_param[i].temperature_z, "temperature_z"))
            {
                species_param[i].temperature_z = 0.0;
            }
            //log_info<<"temperature_z: "<<species_param[i].temperature_z;

            if(!get_class_double_vector(tmp, species_param[i].mean_velocity, "mean_velocity"))
            {
                species_param[i].mean_velocity.resize(3, 0.0);
                //log_info<<"mean_velocity is set to [0, 0, 0] ";
            }

            if(!get_class_int(tmp, species_param[i].timestep_frozen, "timestep_frozen"))
            {

            }

            if(!get_class_string(tmp, species_param[i].bc_part_type_west, "bc_part_type_west"))
            {

            }

            if(!get_class_string(tmp, species_param[i].bc_part_type_east, "bc_part_type_east"))
            {

            }

            if(!get_class_string(tmp, species_param[i].bc_part_type_south, "bc_part_type_south"))
            {

            }

            if(!get_class_string(tmp, species_param[i].bc_part_type_north, "bc_part_type_north"))
            {

            }

            if(!get_class_string(tmp, species_param[i].bc_part_type_bottom, "bc_part_type_bottom"))
            {

            }

            if(!get_class_string(tmp, species_param[i].bc_part_type_up, "bc_part_type_up"))
            {

            }


            //=============== parameters for DSMC ===================================

            if(!get_class_double(tmp, species_param[i].diameter, "diameter"))
            {

            }

            if(!get_class_double(tmp, species_param[i].ref_temperature, "ref_temperature"))
            {

            }

            if(!get_class_double(tmp, species_param[i].visc_temp_index, "visc_temp_index"))
            {

            }

            if(!get_class_double(tmp, species_param[i].vss_scat_inv, "vss_scat_inv"))
            {

            }


            //==============Parameters for physical sputtering and backscattering============
            if(!get_class_int(tmp, species_param[i].atomic_number, "atomic_number"))
            {

            }

            if(!get_class_double(tmp, species_param[i].atomic_mass, "atomic_mass"))
            {

            }

            if(!get_class_double(tmp, species_param[i].surface_binding_energy, "surface_binding_energy"))
            {

            }

            if(!get_class_double(tmp, species_param[i].density_solid, "density_solid"))
            {

            }

            //============Parameters for backscattering as the target
            if(!get_class_int(tmp, species_param[i].ne2, "ne2"))
            {

            }

            if(!get_class_int_vector(tmp, species_param[i].an2_vector, "an2_vector"))
            {

            }

            if(!get_class_int_vector(tmp, species_param[i].nw2_vector, "nw2_vector"))
            {

            }

            //log_info << "read particle boundary condition";

            //read particle boundary condition

            if (tmp.HasMember("ParticleBoundaryCondition"))
            {
                const rapidjson::Value& pbc_array = tmp["ParticleBoundaryCondition"];
                species_param[i].pbc_param.resize(pbc_array.Size());

                for (int j = 0; j < pbc_array.Size(); ++j)
                {
                    const rapidjson::Value& pbc_tmp = pbc_array[j];

                    if (!get_class_string(pbc_tmp, species_param[i].pbc_param[j].edge_name, "edge_name"))
                    {

                    }

                    if (!get_class_string(pbc_tmp, species_param[i].pbc_param[j].pbc_type, "pbc_type"))
                    {

                    }

                    if (!get_class_string(pbc_tmp, species_param[i].pbc_param[j].periodic_edge_name, "periodic_edge_name"))
                    {

                    }
                }
                sort(species_param[i].pbc_param.begin(), species_param[i].pbc_param.end(), greater_sort_pbc);
                for (int j = 0; j < species_param[i].pbc_param.size(); j++)
                {
                    //log_info << "config: pbc " << species_param[i].pbc_param[j].edge_name;
                    species_param[i].particleBoundaryTypeMap[species_param[i].pbc_param[j].edge_name] = species_param[i].pbc_param[j].pbc_type;
                }
            }
            
            //species_param[i].weight = species_param[i].number_density / species_param[i].n_part_per_cell_for_weight;

            //log_info << "reading isWrite";
            if(!get_class_bool(tmp, species_param[i].isWrite, "isWrite"))
            {
                species_param[i].isWrite = true;
            }
            if (species_param[i].species_type == "fluid")
            {
                species_param[i].isWrite = false;
            }

            //log_info << "end reading isWrite";
        }
    }
}


int Config::get_species_number(const std::string &species_name)
{
    for(int i = 0; i < species_param.size(); i++)
    {
        if(species_name == species_param[i].species_name)
        {
            return i;
        }
    }
    log_error<<"no species name: "<<species_name;
    exit(0);
    return -1;
}


void Config::read_particle_source()
{
    if(dom.HasMember("ParticleSource") && dom["ParticleSource"].IsArray())
    {
        const rapidjson::Value& arr = dom["ParticleSource"];
        particle_source_param.resize(arr.Size());
        for(int i = 0; i < arr.Size(); ++i)
        {
            const rapidjson::Value& tmp = arr[i];

            if(!get_class_string(tmp, particle_source_param[i].species_name, "species_name"))
            {

            }
            else
            {
                particle_source_param[i].species_number = get_species_number(particle_source_param[i].species_name);
                //log_info<<"read_particle_source: "<<particle_source_param[i].species_number;

            }

            if(!get_class_string(tmp, particle_source_param[i].species_name_dependent, "species_name_dependent"))
            {

            }
            else
            {
                particle_source_param[i].species_number_dependent = get_species_number(particle_source_param[i].species_name_dependent);

            }


            if(!get_class_string(tmp, particle_source_param[i].ps_type, "ps_type"))
            {

            }

            if(!get_class_string(tmp, particle_source_param[i].load_type, "load_type"))
            {

            }

            if(!get_class_string(tmp, particle_source_param[i].emitType, "emitType"))
            {
                if (particle_source_param[i].ps_type == "emit" && particle_source_param[i].emitType == "")
                {
                    log_error << "emitType not given";
                    exit(0);
                }
            }

            if (!get_class_string(tmp, particle_source_param[i].emitCoordinateSystem, "emitCoordinateSystem"))
            {
                particle_source_param[i].emitCoordinateSystem = "local";
            }


            if (!get_class_double(tmp, particle_source_param[i].workFunction, "workFunction"))
            {

            }

            if (!get_class_double(tmp, particle_source_param[i].surfaceTemperature, "surfaceTemperature"))
            {

            }

            if (!get_class_double(tmp, particle_source_param[i].A, "A"))
            {
                particle_source_param[i].A = 120.0;
            }

            if(!get_class_double(tmp, particle_source_param[i].number_density, "number_density"))
            {

            }

            if(!get_class_double(tmp, particle_source_param[i].dn, "dn"))
            {

            }

            if(!get_class_double(tmp, particle_source_param[i].dq, "dq"))
            {

            }

            if(!get_class_double(tmp, particle_source_param[i].dn_scale_down, "dn_scale_down"))
            {
                particle_source_param[i].dn_scale_down = 10.0;
            }

            if(!get_class_double(tmp, particle_source_param[i].load_particle_number, "load_particle_number"))
            {
                int load_particle_number_temp;
                if (get_class_int(tmp, load_particle_number_temp, "load_particle_number"))
                {
                    particle_source_param[i].load_particle_number = load_particle_number_temp;
                }
            }


            if(!get_class_double(tmp, particle_source_param[i].temperature, "temperature"))
            {

            }

            if(!get_class_double_vector(tmp, particle_source_param[i].mean_velocity, "mean_velocity"))
            {
                particle_source_param[i].mean_velocity.resize(3);
                particle_source_param[i].mean_velocity[0] = 0.0;
                particle_source_param[i].mean_velocity[1] = 0.0;
                particle_source_param[i].mean_velocity[2] = 0.0;
            }
            //log_info << "[Config.cpp::read_particle_source] mean_velocity " << particle_source_param[i].mean_velocity[0] << " " << particle_source_param[i].mean_velocity[1] << " " << particle_source_param[i].mean_velocity[2];

            if(!get_class_double_vector(tmp, particle_source_param[i].load_position_start, "load_position_start"))
            {

            }

            if(!get_class_double_vector(tmp, particle_source_param[i].load_position_end, "load_position_end"))
            {

            }

            if(!get_class_double_vector(tmp, particle_source_param[i].load_box, "load_box"))
            {

            }

            if(!get_class_double_vector(tmp, particle_source_param[i].timeDuration, "timeDuration"))
            {
                particle_source_param[i].timeDuration.resize(2);
                particle_source_param[i].timeDuration[0] = 0.0;
                particle_source_param[i].timeDuration[1] = 1.0;
            }
            

            if(!get_class_int(tmp, particle_source_param[i].timestep_update, "timestep_update"))
            {
                particle_source_param[i].timestep_update = 1;
            }

            if(!get_class_bool(tmp, particle_source_param[i].is_dependent, "is_dependent"))
            {

            }

            if(!get_class_bool(tmp, particle_source_param[i].is_every_time, "is_every_time"))
            {
                particle_source_param[i].is_every_time = true;
            }

            if(!get_class_double(tmp, particle_source_param[i].emit_particle_number, "emit_particle_number"))
            {

            }

            if(!get_class_double(tmp, particle_source_param[i].emit_flux, "emit_flux"))
            {

            }

            if (!get_class_string(tmp, particle_source_param[i].emitFluxString, "emitFluxString"))
            {
                if (particle_source_param[i].emitType == "fluxVaryingWithTime")
                {
                    log_error << "fluxVaryingWithTime should set emitFluxString";
                    exit(0);
                }
            }

            if(!get_class_string(tmp, particle_source_param[i].emit_position, "emit_position"))
            {

            }

            if(!get_class_double(tmp, particle_source_param[i].emit_offset, "emit_offset"))
            {
                particle_source_param[i].emit_offset = 0.2;
            }
            
            if(!get_class_double(tmp, particle_source_param[i].emit_velocity, "emit_velocity"))
            {
                particle_source_param[i].emit_velocity = 0.0;
            }


            if (!get_class_double_vector(tmp, particle_source_param[i].emitVelocityVector, "emitVelocityVector"))
            {

            }

            if (!get_class_bool(tmp, particle_source_param[i].isDepositOppositeCharge, "isDepositOppositeCharge"))
            {
                particle_source_param[i].isDepositOppositeCharge = false;
            }
            

            //if (!get_class_string(tmp, particle_source_param[i].emitVelocityType, "emitVelocityType"))
            //{
            //    particle_source_param[i].emitVelocityType = "directionMaxwellian";
            //}

            if(!get_class_string(tmp, particle_source_param[i].edge_name, "edge_name"))
            {
                
            }

            if (!get_class_string(tmp, particle_source_param[i].profileFilterString, "profileFilterString"))
            {
                particle_source_param[i].profileFilterString = "1.0";
            }

            if (!get_class_bool(tmp, particle_source_param[i].isFixNTV, "isFixNTV"))
            {
                particle_source_param[i].isFixNTV = false;
            }

            if (!get_class_double(tmp, particle_source_param[i].emitCurrentDensity, "emitCurrentDensity"))
            {
                particle_source_param[i].emitCurrentDensity = 0.0;
            }

            if (!get_class_double(tmp, particle_source_param[i].scatteringAngle, "scatteringAngle"))
            {
                particle_source_param[i].scatteringAngle = 0.0;
            }

            if (!get_class_double_vector(tmp, particle_source_param[i].lightDirection, "lightDirection"))
            {
                
            }
        }
    }
}


void Config::read_collision()
{
    if(dom.HasMember("Collision") && dom["Collision"].IsArray())
    {
        if(debugLevel > 0) log_info << "--------- begin: read collision"; 
        const rapidjson::Value& arr = dom["Collision"];
        collision_param.resize(arr.Size());
        for(int i = 0; i < arr.Size(); ++i)
        {
            const rapidjson::Value& tmp = arr[i];


            if(!get_class_string(tmp, collision_param[i].reaction_name, "reaction_name"))
            {
                collision_param[i].reaction_name = "none";
                log_error << "not found collision type";
            }

            if (!get_class_string(tmp, collision_param[i].reaction_type, "reaction_type"))
            {
                log_error << "not found reaction_type";
                exit(0);
            }

            //Now only support json cross section file, not support text format file
            //if (!get_class_string(tmp, collision_param[i].cs_file_name, "cs_file_name"))
            //{
            //    log_warning << "not found cross section file name";
            //    collision_param[i].cs_file_name = "";
            //}
            

            if (!get_class_string(tmp, collision_param[i].collisionAlgorithm, "collisionAlgorithm"))
            {
                collision_param[i].collisionAlgorithm = "reaction";
            }

            if(!get_class_string_vector(tmp, collision_param[i].species_left_list, "species_left_list"))
            {

            }

            if (!get_class_string_vector(tmp, collision_param[i].species_right_list, "species_right_list"))
            {

            }


            if(!get_class_int(tmp, collision_param[i].reaction_id, "reaction_id"))
            {
                collision_param[i].reaction_id = -1;
            }

            if(!get_class_int(tmp, collision_param[i].timestep_collision, "timestep_collision"))
            {
                collision_param[i].timestep_collision = 1;
            }

            if(!get_class_double(tmp, collision_param[i].time_zoom_factor, "time_zoom_factor"))
            {
                collision_param[i].time_zoom_factor = 1.0;
            }

            if (!get_class_double(tmp, collision_param[i].ionizationEnergy, "ionizationEnergy"))
            {
                if (collision_param[i].reaction_type == "field ionization")
                {
                    log_error << "field ionization collision should set ionizationEnergy";
                    exit(0);
                }
            }

            //===========================================================更新了数据库，不再重命名反应类型，也不再对反应前后组分进行重新排序==========================
            ////rename reaction_type
            //if (collision_param[i].reaction_type == "recombination")
            //{
            //    if (collision_param[i].species_left_list.size() == 2)
            //    {
            //        collision_param[i].reaction_type == "binary recombination";
            //    }
            //    else if(collision_param[i].species_left_list.size() == 3)
            //    {
            //        collision_param[i].reaction_type == "three body recombination";
            //    }
            //    else
            //    {
            //        log_error << "not support this collision";
            //        exit(0);
            //    }
            //}
            //else if (collision_param[i].reaction_type == "attached")
            //{
            //    collision_param[i].reaction_type == "electron attachment";
            //}

            //


            ////求解器组分列表顺序是固定的，因此这里需要排序
            ////电离反应：e + Mol -> e + e + Ion, 电子e的名称是固定的："e^{-}"，按这个进行重排
            //if (collision_param[i].reaction_type == "ionization" || collision_param[i].reaction_type == "excitation" || collision_param[i].reaction_type == "elastic")
            //{
            //    for (auto& speciesName : collision_param[i].species_left_list)
            //    {
            //        if (speciesName == "e^{-}")
            //        {
            //            collision_param[i].species_name_list.push_back(speciesName);
            //        }
            //    }
            //    for (auto& speciesName : collision_param[i].species_left_list)
            //    {
            //        if (speciesName != "e^{-}")
            //        {
            //            collision_param[i].species_name_list.push_back(speciesName);
            //        }
            //    }

            //    for (auto& speciesName : collision_param[i].species_right_list)
            //    {
            //        if (speciesName == "e^{-}")
            //        {
            //            collision_param[i].species_name_list.push_back(speciesName);
            //        }
            //    }
            //    for (auto& speciesName : collision_param[i].species_right_list)
            //    {
            //        if (speciesName != "e^{-}")
            //        {
            //            collision_param[i].species_name_list.push_back(speciesName);
            //        }
            //    }
            //}

            ////charge exchange： A^{+} + B -> A + B^{+}, species order must be fixed like this, so speces_name_list should be reorderd first.
            //else if (collision_param[i].reaction_type == "charge exchange")
            //{
            //    for (auto& speciesName : collision_param[i].species_left_list)
            //    {
            //        int species_number = get_species_number(speciesName);
            //        double charge = species_param[species_number].charge;
            //        if (charge != 0.0)
            //        {
            //            collision_param[i].species_name_list.push_back(speciesName);
            //        }
            //    }
            //    for (auto& speciesName : collision_param[i].species_left_list)
            //    {
            //        int species_number = get_species_number(speciesName);
            //        double charge = species_param[species_number].charge;
            //        if (charge == 0.0)
            //        {
            //            collision_param[i].species_name_list.push_back(speciesName);
            //        }
            //    }

            //    for (auto& speciesName : collision_param[i].species_right_list)
            //    {
            //        int species_number = get_species_number(speciesName);
            //        double charge = species_param[species_number].charge;
            //        if (charge == 0.0)
            //        {
            //            collision_param[i].species_name_list.push_back(speciesName);
            //        }
            //    }
            //    for (auto& speciesName : collision_param[i].species_right_list)
            //    {
            //        int species_number = get_species_number(speciesName);
            //        double charge = species_param[species_number].charge;
            //        if (charge != 0.0)
            //        {
            //            collision_param[i].species_name_list.push_back(speciesName);
            //        }
            //    }
            //}

            ////recombination: e + A^{+} -> A; A^{-} + B^{+} ->AB
            //else if (collision_param[i].reaction_type == "binary recombination" || collision_param[i].reaction_type == "three body recombination")
            //{
            //    for (auto& speciesName : collision_param[i].species_left_list)
            //    {
            //        int species_number = get_species_number(speciesName);
            //        double mass = species_param[species_number].mass;
            //        //first electron
            //        if (mass < 1.1 * const_emass)
            //        {
            //            collision_param[i].species_name_list.push_back(speciesName);
            //        }
            //    }
            //    for (auto& speciesName : collision_param[i].species_left_list)
            //    {
            //        int species_number = get_species_number(speciesName);
            //        double charge = species_param[species_number].charge;
            //        double mass = species_param[species_number].mass;
            //        //second negtive ion
            //        if (charge < 0.0 && mass > 1.1 * const_emass)
            //        {
            //            collision_param[i].species_name_list.push_back(speciesName);
            //        }
            //    }

            //    for (auto& speciesName : collision_param[i].species_left_list)
            //    {
            //        int species_number = get_species_number(speciesName);
            //        double charge = species_param[species_number].charge;
            //        double mass = species_param[species_number].mass;
            //        //third positive ion
            //        if (charge > 0.0 && mass > 1.1 * const_emass)
            //        {
            //            collision_param[i].species_name_list.push_back(speciesName);
            //        }
            //    }

            //    //right
            //    for (auto& speciesName : collision_param[i].species_right_list)
            //    {
            //        int species_number = get_species_number(speciesName);
            //        double mass = species_param[species_number].mass;
            //        //first electron
            //        if (mass < 1.1 * const_emass)
            //        {
            //            collision_param[i].species_name_list.push_back(speciesName);
            //        }
            //    }
            //    for (auto& speciesName : collision_param[i].species_right_list)
            //    {
            //        int species_number = get_species_number(speciesName);
            //        double mass = species_param[species_number].mass;
            //        //second others
            //        if (mass > 1.1 * const_emass)
            //        {
            //            collision_param[i].species_name_list.push_back(speciesName);
            //        }
            //    }
            //}

            ////electron attachment: e + A -> A^{-};
            //else if (collision_param[i].reaction_type == "electron attachment")
            //{
            //    for (auto& speciesName : collision_param[i].species_left_list)
            //    {
            //        int species_number = get_species_number(speciesName);
            //        double mass = species_param[species_number].mass;
            //        //first electron
            //        if (mass < 1.1 * const_emass)
            //        {
            //            collision_param[i].species_name_list.push_back(speciesName);
            //        }
            //    }
            //    for (auto& speciesName : collision_param[i].species_left_list)
            //    {
            //        int species_number = get_species_number(speciesName);
            //        double mass = species_param[species_number].mass;
            //        if (mass > 1.1 * const_emass)
            //        {
            //            collision_param[i].species_name_list.push_back(speciesName);
            //        }
            //    }


            //    //right
            //    for (auto& speciesName : collision_param[i].species_right_list)
            //    {
            //        collision_param[i].species_name_list.push_back(speciesName);
            //    }

            //}
            //else
            //{
            //    for (auto& speciesName : collision_param[i].species_left_list)
            //    {
            //        int species_number = get_species_number(speciesName);
            //        double mass = species_param[species_number].mass;
            //        collision_param[i].species_name_list.push_back(speciesName);
            //    }


            //    //right
            //    for (auto& speciesName : collision_param[i].species_right_list)
            //    {
            //        collision_param[i].species_name_list.push_back(speciesName);
            //    }
            //}

            for (auto& speciesName : collision_param[i].species_left_list)
            {
                collision_param[i].species_name_list.push_back(speciesName);
            }
            for (auto& speciesName : collision_param[i].species_right_list)
            {
                collision_param[i].species_name_list.push_back(speciesName);
            }


            if (debugLevel > 0) log_info << "collision id: " << i;
            for (auto& speciesName : collision_param[i].species_name_list)
            {
                int species_number = get_species_number(speciesName);
                collision_param[i].species_number_list.push_back(species_number);
                if (debugLevel > 0) log_info << "---species name: " << speciesName;
            }
        }
        if (debugLevel > 0) log_info << "--------- end: read collision";

        if (collision_param.size() == 0)
        {
            return;
        }


        //=============read cross section from database=======================================================
        if (debugLevel > 0) log_info << std::endl;
        if (debugLevel > 0) log_info << "------------------- begin: read cross section";
       
        std::string reactionDataBaseName = dataBaseDir + "/reaction.database";
        std::ifstream in(reactionDataBaseName.c_str());
        if (!in.is_open())
        {
            log_error << "fail to read input file: data/easypic3d.json";
        }

        std::string json_content((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
        in.close();

        rapidjson::Document reactionDom;
        if (reactionDom.Parse(json_content.c_str()).HasParseError())
        {
            log_error << "params reactionDom error at offset " << reactionDom.GetErrorOffset() << ": " << GetParseError_En(reactionDom.GetParseError());
        }

        if (reactionDom.IsArray())
        {
            for (int iCollision = 0; iCollision < collision_param.size(); iCollision++)
            {
                auto& collisionParamIterm = collision_param[iCollision];

                if (collision_param[iCollision].reaction_id < 0)
                {
                    log_error << "error, reaction_id: " << collision_param[iCollision].reaction_id;
                    exit(0);
                }

                int numReaction = reactionDom.Size();
                //log_info << "reaction database number: " << numReaction;
                for (int iReactionDatabase = 0; iReactionDatabase < numReaction; iReactionDatabase++)
                {
                    const rapidjson::Value& tmp = reactionDom[iReactionDatabase];
                    int reactionId = -1;
                    if (get_class_int(tmp, reactionId, "reaction_id"))
                    {
                        if (reactionId == collision_param[iCollision].reaction_id)
                        {
                            //int reaction_rate_type = -1;
                            //if (get_class_int(tmp, reaction_rate_type, "reaction_rate_type"))
                            //{
                            //    log_error << "not found reaction_rate_type";
                            //}
                            //if (reaction_rate_type != 0)
                            //{
                            //    log_error << "data is not cross section, reaction_rate_type = " << reaction_rate_type;
                            //    exit(0);
                            //}

                            if (debugLevel > 0) log_info << "reactionId: " << reactionId;

                            std::vector<double> C_cross;
                            std::vector<double> C_energe;
                            get_class_double_vector(tmp, C_cross, "C_cross");
                            get_class_double_vector(tmp, C_energe, "C_energe");
                            if (C_energe.size() != C_cross.size())
                            {
                                log_error << "energy and cross section vector size not match";
                                exit(0);
                            }
                            collision_param[iCollision].cross_section.push_back(C_energe);
                            collision_param[iCollision].cross_section.push_back(C_cross);

                            if(this->debugLevel > 1) log_info << "-------------- cross setion -------------------";
                            for (int i = 0; i < collision_param[iCollision].cross_section[1].size(); i++)
                            {
                                if (this->debugLevel > 1) log_info << collision_param[iCollision].cross_section[0][i] << " " << collision_param[iCollision].cross_section[1][i];
                            }
                            


                            break;
                        }
                        else
                        {

                        }
                    }
                }

            }
        }
        else
        {
            log_error << "reactionDom is not json array";
            exit(0);
        }
        if (debugLevel > 0) log_info << "------------------- end: read cross section";

        //=============end read cross section=======================================================

    }



}


void Config::read_psi()
{
    if(dom.HasMember("PSI") && dom["PSI"].IsArray())
    {
        const rapidjson::Value& arr = dom["PSI"];
        psi_param.resize(arr.Size());
        for(int i = 0; i < arr.Size(); ++i)
        {
            const rapidjson::Value& tmp = arr[i];

            if(!get_class_string(tmp, psi_param[i].edge_name, "edge_name"))
            {

            }

            if(!get_class_string(tmp, psi_param[i].psi_type, "psi_type"))
            {

            }

            if(!get_class_string_vector(tmp, psi_param[i].species_name_list, "species_name_list"))
            {

            }
            else
            {
                psi_param[i].species_number_list.resize(psi_param[i].species_name_list.size());
                for(int j = 0; j < psi_param[i].species_name_list.size(); j++)
                {
                    psi_param[i].species_number_list[j] = get_species_number(psi_param[i].species_name_list[j]);
                }
            }

            if(!get_class_double(tmp, psi_param[i].emit_offset, "emit_offset"))
            {
                psi_param[i].emit_offset = 0.1;
            }

            if(!get_class_bool(tmp, psi_param[i].is_self_consistent, "is_self_consistent"))
            {
                psi_param[i].is_self_consistent = true;
            }

            if(!get_class_string(tmp, psi_param[i].psi_position, "psi_position"))
            {

            }

            if(!get_class_double(tmp, psi_param[i].recycling_factor, "recycling_factor"))
            {

            }

            if(!get_class_double(tmp, psi_param[i].recycling_temperature, "recycling_temperature"))
            {

            }

            if(!get_class_double(tmp, psi_param[i].temperature, "temperature"))
            {

            }

            if(!get_class_string(tmp, psi_param[i].sec, "sec"))
            {

            }

            if(!get_class_double(tmp, psi_param[i].randomSecLimit, "randomSecLimit"))
            {
                psi_param[i].randomSecLimit = 0.0;
            }

            if (!get_class_int(tmp, psi_param[i].emitPlusNumber, "emitPlusNumber"))
            {
                psi_param[i].emitPlusNumber = 0;
            }
            

            if(!get_class_string(tmp, psi_param[i].velocityType, "velocityType"))
            {
                 psi_param[i].velocityType = "maxwell";
            } 

            if (!get_class_string(tmp, psi_param[i].psiAlgorithm, "psiAlgorithm"))
            {
                psi_param[i].psiAlgorithm = "always";
                //psi_param[i].psiAlgorithm = "random";
            }

            if (!get_class_bool(tmp, psi_param[i].isDepositOppositeCharge, "isDepositOppositeCharge"))
            {
                psi_param[i].isDepositOppositeCharge = false;
            }

        }
    }
}


void Config::read_diagnostic()
{
    if(dom.HasMember("Diagnostic") && dom["Diagnostic"].IsArray())
    {
        const rapidjson::Value& arr = dom["Diagnostic"];
        diagnostic_param.resize(arr.Size());
        for(int i = 0; i < arr.Size(); ++i)
        {
            const rapidjson::Value& tmp = arr[i];

            if(!get_class_int(tmp, diagnostic_param[i].vedf_n_velocity, "vedf_n_velocity"))
            {

            }

            if(!get_class_double_vector(tmp, diagnostic_param[i].edf_max_energy, "edf_max_energy"))
            {

            }


            if(!get_class_string_vector(tmp, diagnostic_param[i].vedf_species_name_list, "vedf_species_name_list"))
            {

            }
            else
            {
                diagnostic_param[i].vedf_species_number_list.resize(diagnostic_param[i].vedf_species_name_list.size());
                for(int j = 0; j < diagnostic_param[i].vedf_species_name_list.size(); j++)
                {
                    diagnostic_param[i].vedf_species_number_list[j] = get_species_number(diagnostic_param[i].vedf_species_name_list[j]);
                }

                diagnostic_param[i].vedf_n_species = diagnostic_param[i].vedf_species_number_list.size();
            }

            if(!get_class_double_vector(tmp, diagnostic_param[i].vedf_position, "vedf_position"))
            {

            }
            else
            {
                diagnostic_param[i].vedf_n_position = diagnostic_param[i].vedf_position.size();
            }
        }
    }
}




void Config::read_simulation_time()
{
    if(dom.HasMember("SimulationTime"))
    {
        const rapidjson::Value& tmp = dom["SimulationTime"];

        if(!get_class_double(tmp, sim_time_param.dt, "dt"))
        {

        }

        if(!get_class_int(tmp, sim_time_param.timestep_simulation, "timestep_simulation"))
        {

        }

        if(!get_class_int(tmp, sim_time_param.timestep_io, "timestep_io"))
        {

        }

        if(!get_class_int(tmp, sim_time_param.timestep_average, "timestep_average"))
        {

        }

        if(!get_class_int(tmp, sim_time_param.timestep_collision, "timestep_collision"))
        {

        }

        if(!get_class_int(tmp, sim_time_param.timestep_coulomb, "timestep_coulomb"))
        {

        }

        if(!get_class_int(tmp, sim_time_param.timestep_DSMC, "timestep_DSMC"))
        {

        }

        if(!get_class_int(tmp, sim_time_param.timestep_restore, "timestep_restore"))
        {

        }

        if (!get_class_bool(tmp, sim_time_param.isReload, "isReload"))
        {
            sim_time_param.isReload = false;
        }

        if (!get_class_int(tmp, sim_time_param.reloadIOstep, "reloadIOstep"))
        {
            sim_time_param.reloadIOstep = 0;
        }


        if (!get_class_bool(tmp, sim_time_param.isChargeDepositAccelerate, "isChargeDepositAccelerate"))
        {
            sim_time_param.isChargeDepositAccelerate = false;
        }

        if (!get_class_int(tmp, sim_time_param.timestepSteady, "timestepSteady"))
        {

        }

        if (!get_class_int(tmp, sim_time_param.timestepAccelerate, "timestepAccelerate"))
        {

        }

        if (!get_class_double(tmp, sim_time_param.maxAccelerateFactorK, "maxAccelerateFactorK"))
        {
            sim_time_param.maxAccelerateFactorK = 1.0e6;
        }
    }
}

void Config::readMeshParameter()
{
    if (dom.HasMember("Mesh"))
    {
        const rapidjson::Value& tmp = dom["Mesh"];

        if (!get_class_string(tmp, mesh_param.meshName, "meshName"))
        {
            log_error << "there is no mesh";
            exit(0);
        }
        else
        {
            mesh_param.meshName = "input/" + mesh_param.meshName;
        }

        if (!get_class_double(tmp, mesh_param.meshScale, "meshScale"))
        {
            mesh_param.meshScale = 1.0;
        }

        if (tmp.HasMember("PeriodicBoundary") && tmp["PeriodicBoundary"].IsArray())
        {
            const rapidjson::Value& arr = tmp["PeriodicBoundary"];
            mesh_param.mesh_periodic_edge0.resize(arr.Size());
            mesh_param.mesh_periodic_edge1.resize(arr.Size());
            for (int i = 0; i < arr.Size(); ++i)
            {
                const rapidjson::Value& tmp1 = arr[i];
                if (!get_class_string(tmp1, mesh_param.mesh_periodic_edge0[i], "boundary1"))
                {
                }
                if (!get_class_string(tmp1, mesh_param.mesh_periodic_edge1[i], "boundary2"))
                {
                }
                log_info << "mesh_periodic_edge0: " << mesh_param.mesh_periodic_edge0[i];
                log_info << "mesh_periodic_edge1: " << mesh_param.mesh_periodic_edge1[i];
            }
        }

        for (int i = 0; i < mesh_param.mesh_periodic_edge0.size(); i++)
        {
            mesh_param.periodicFaceGroupMap[mesh_param.mesh_periodic_edge0[i]] = mesh_param.mesh_periodic_edge1[i];
            mesh_param.periodicFaceGroupMapReverse[mesh_param.mesh_periodic_edge1[i]] = mesh_param.mesh_periodic_edge0[i];
        }


        if(debugLevel > 0) log_info << "--------- begin: material info";
        if (tmp.HasMember("Material") && tmp["Material"].IsArray())
        {
            const rapidjson::Value& arr = tmp["Material"];
            for (int i = 0; i < arr.Size(); ++i)
            {
                std::string physicalGroupName;
                std::string materialName;
                const rapidjson::Value& tmp1 = arr[i];
                if (!get_class_string(tmp1, physicalGroupName, "physicalGroupName"))
                {
                }
                if (!get_class_string(tmp1, materialName, "materialName"))
                {
                }
                mesh_param.physicalGroupToMaterialMap[physicalGroupName] = materialName;
                log_info << "physicalGroupName: " << physicalGroupName;
                log_info << "materialName: " << materialName;
            }
        }
        if (debugLevel > 0) log_info << "--------- end: material info";
    }
}

void Config::readElectroMagneticFieldParameter()
{
    if (dom.HasMember("ElectroMagneticField"))
    {
        const rapidjson::Value& tmp = dom["ElectroMagneticField"];

        if (!get_class_string(tmp, em_param.externalFieldString, "externalFieldString"))
        {
            em_param.externalFieldString = "var ETemp[3] := {0.0, 0.0, 0.0}; var BTemp[3] := {0.0, 0.0, 0.0};  E := ETemp; B := BTemp;";
        }

        if (!get_class_bool(tmp, em_param.isSolveEM, "isSolveEM"))
        {
            em_param.isSolveEM = true;
        }
        
        if (!get_class_string(tmp, em_param.solverType, "solverType"))
        {
            em_param.solverType = "hypre";
        }

        if (!get_class_double(tmp, em_param.solverRelativeTolerance, "solverRelativeTolerance"))
        {
            em_param.solverRelativeTolerance = 1.0e-6;
        }

        if (!get_class_int(tmp, em_param.solverNumSweeps, "solverNumSweeps"))
        {
            em_param.solverNumSweeps = 1;
        }

        if (!get_class_int(tmp, em_param.solverMaxLevels, "solverMaxLevels"))
        {
            em_param.solverMaxLevels = 30;
        }

        if (!get_class_int(tmp, em_param.solverRelaxType, "solverRelaxType"))
        {
            em_param.solverRelaxType = 3;
        }

        if (!get_class_int(tmp, em_param.solverRelaxOrder, "solverRelaxOrder"))
        {
            em_param.solverRelaxOrder = 1;
        }


        if (tmp.HasMember("FieldBoundaryCondition") && tmp["FieldBoundaryCondition"].IsArray())
        {
            const rapidjson::Value& arr = tmp["FieldBoundaryCondition"];
            em_param.fbc_param.resize(arr.Size());
            for (int i = 0; i < arr.Size(); ++i)
            {
                FieldBoundaryConditionParameter* fieldBoundaryConditionParameter = new FieldBoundaryConditionParameter();
                em_param.fbc_param[i] = fieldBoundaryConditionParameter;

                const rapidjson::Value& tmp1 = arr[i];

                if (!get_class_string(tmp1, fieldBoundaryConditionParameter->field_name, "field_name"))
                {

                }

                if (!get_class_string(tmp1, fieldBoundaryConditionParameter->fbc_name, "fbc_name"))
                {

                }
                if (debugLevel > 1) log_info << "boundaryName: " << fieldBoundaryConditionParameter->fbc_name;

                if (!get_class_string(tmp1, fieldBoundaryConditionParameter->fbc_type, "fbc_type"))
                {

                }
                if (debugLevel > 1) log_info << "boundary type: " << fieldBoundaryConditionParameter->fbc_type;

                if (!get_class_double(tmp1, fieldBoundaryConditionParameter->fbc_value, "fbc_value"))
                {

                }
                else
                {
                    //ref 4.85b, robin approximation: -n(a detau) = k(u-gd)-gn
                    if (fieldBoundaryConditionParameter->fbc_type == "dirichlet")
                    {
                        fieldBoundaryConditionParameter->fbc_robin_k = 1.0e20;
                        fieldBoundaryConditionParameter->fbc_robin_gd = em_param.fbc_param[i]->fbc_value;
                        fieldBoundaryConditionParameter->fbc_robin_gn = 0.0;
                    }
                    else if (fieldBoundaryConditionParameter->fbc_type == "neumann")
                    {
                        fieldBoundaryConditionParameter->fbc_robin_k = 0.0;
                        fieldBoundaryConditionParameter->fbc_robin_gd = 0.0;
                        fieldBoundaryConditionParameter->fbc_robin_gn = em_param.fbc_param[i]->fbc_value;
                    }

                }

                if (!get_class_string(tmp1, fieldBoundaryConditionParameter->fbcValueString, "fbcValueString"))
                {
                    fieldBoundaryConditionParameter->fbcValueString = "";
                }



                if (!get_class_double(tmp1, fieldBoundaryConditionParameter->fbc_robin_k, "fbc_robin_k"))
                {

                }

                if (!get_class_double(tmp1, fieldBoundaryConditionParameter->fbc_robin_gd, "fbc_robin_gd"))
                {

                }

                if (!get_class_double(tmp1, fieldBoundaryConditionParameter->fbc_robin_gn, "fbc_robin_gn"))
                {

                }

                if (!get_class_double(tmp1, fieldBoundaryConditionParameter->fixedPower, "fixedPower"))
                {
                    fieldBoundaryConditionParameter->fixedPower = 0.0;
                }

                fieldBoundaryConditionParameter->compile();

                if (fieldBoundaryConditionParameter->fbc_type == "float")
                {
                    fieldBoundaryConditionParameter->fbc_type = "dirichlet";
                    fieldBoundaryConditionParameter->calValue(0.0);
                    fieldBoundaryConditionParameter->fbc_type = "float";

                    log_info << "float fbc_value: " << fieldBoundaryConditionParameter->fbc_value;
                }

                if (!get_class_double(tmp1, fieldBoundaryConditionParameter->capacityCii, "capacityCii"))
                {
                    fieldBoundaryConditionParameter->capacityCii = 0.0;
                }

                if (!get_class_double(tmp1, fieldBoundaryConditionParameter->accumlatedCharge, "accumlatedCharge"))
                {
                    fieldBoundaryConditionParameter->accumlatedCharge = 0.0;
                }

                //read externalCircuitType
                if (!get_class_string(tmp1, fieldBoundaryConditionParameter->externalCircuitType, "externalCircuitType"))
                {
                    fieldBoundaryConditionParameter->externalCircuitType = "";
                }

                if (!get_class_double(tmp1, fieldBoundaryConditionParameter->rlcR, "rlcR"))
                {
                    fieldBoundaryConditionParameter->rlcR = 0.0;
                }

                if (!get_class_double(tmp1, fieldBoundaryConditionParameter->rlcL, "rlcL"))
                {
                    fieldBoundaryConditionParameter->rlcL = 0.0;
                }

                if (!get_class_double(tmp1, fieldBoundaryConditionParameter->rlcC, "rlcC"))
                {
                    fieldBoundaryConditionParameter->rlcC = 0.0;
                }

                if (!get_class_double(tmp1, fieldBoundaryConditionParameter->rlcQCt, "rlcQCt"))
                {
                    fieldBoundaryConditionParameter->rlcQCt = 0.0;
                }

            }
        }


        if (!get_class_string(tmp, em_param.externalMagneticFieldFromPegasusFileName, "externalMagneticFieldFromPegasusFileName"))
        {
            em_param.externalMagneticFieldFromPegasusFileName = "";
        }
        else
        {
            
        }
        
        if (!get_class_string(tmp, em_param.floatBoundaryMethod, "floatBoundaryMethod"))
        {
            //em_param.floatBoundaryMethod = "iterationMethod"; 
            em_param.floatBoundaryMethod = "capacitanceMatrixMethod"; 
        }
        
        if (!get_class_string(tmp, em_param.externalMagneticFieldString, "externalMagneticFieldString"))
        {
            em_param.externalMagneticFieldString = "";
        }

        if (tmp.HasMember("voltageConnection") && tmp["voltageConnection"].IsArray())
        {
            const rapidjson::Value& arr = tmp["voltageConnection"];
            em_param.voltageConnectionVector.resize(arr.Size());

            for (int i = 0; i < arr.Size(); ++i)
            {
                const rapidjson::Value& arr1 = arr[i];

                if (arr1.IsArray())
                {
                    for (int j = 0; j < arr1.Size(); j++)
                    {
                        const rapidjson::Value& boundaryName = arr1[j];
                        em_param.voltageConnectionVector[i].push_back(boundaryName.GetString());
                        if(debugLevel > 1) log_info << "boundaryName: " << boundaryName.GetString();
                    }
                }
                else
                {
                    log_error << "voltageConnectionVector should be 2d array";
                    exit(0);
                }
            }
        }

        if (tmp.HasMember("resistanceConnection") && tmp["resistanceConnection"].IsArray())
        {
            const rapidjson::Value& arr = tmp["resistanceConnection"];
            em_param.resistanceConnectionParameterList.resize(arr.Size());
            for (int i = 0; i < arr.Size(); ++i)
            {
                const rapidjson::Value& tmp1 = arr[i];

                ResistanceConnectionParameter& resistanceConnectionParameter = em_param.resistanceConnectionParameterList[i];

                if (!get_class_string(tmp1, resistanceConnectionParameter.boundaryName1, "boundaryName1"))
                {

                }

                if (!get_class_string(tmp1, resistanceConnectionParameter.boundaryName2, "boundaryName2"))
                {

                }

                if (!get_class_double(tmp1, resistanceConnectionParameter.resistance, "resistance"))
                {

                }
            }
        }



    }
}


void Config::readElectroMagneticFieldDGTDparameter()
{
    if (dom.HasMember("ElectroMagneticFieldDGTD"))
    {
        const rapidjson::Value& tmp = dom["ElectroMagneticFieldDGTD"];

        if (!get_class_int(tmp, emDGTD_param.femOrder, "femOrder"))
        {
            emDGTD_param.femOrder = 1;
        }

        if (!get_class_bool(tmp, emDGTD_param.isTM, "isTM"))
        {
            emDGTD_param.isTM = true;
        }

        if (!get_class_double(tmp, emDGTD_param.magneticPermeability, "magneticPermeability"))
        {
            emDGTD_param.magneticPermeability = 1.25664e-6;
        }

        if (!get_class_double(tmp, emDGTD_param.dielectricConstant, "dielectricConstant"))
        {
            emDGTD_param.dielectricConstant = 8.85419e-12;
        }

        if (!get_class_double(tmp, emDGTD_param.upmlThickness, "upmlThickness"))
        {
            emDGTD_param.upmlThickness = 0.0;
        }

        if (!get_class_int(tmp, emDGTD_param.upmlM, "upmlM"))
        {
            emDGTD_param.upmlM = 4;
        }

        if (!get_class_int(tmp, emDGTD_param.upmlN, "upmlN"))
        {
            emDGTD_param.upmlN = 1;
        }

        if (!get_class_bool(tmp, emDGTD_param.isReal, "isReal"))
        {
            emDGTD_param.isReal = true;
        }



        if (!get_class_bool(tmp, emDGTD_param.isCalRCS, "isCalRCS"))
        {
            emDGTD_param.isCalRCS = false;
        }

        if (!get_class_int(tmp, emDGTD_param.extr_steps, "extr_steps"))
        {
            emDGTD_param.extr_steps = 1;
        }

        if (!get_class_string(tmp, emDGTD_param.electronDensityString, "electronDensityString"))
        {
            emDGTD_param.electronDensityString = "";
        }

        if (!get_class_string(tmp, emDGTD_param.electronDensityFileName, "electronDensityFileName"))
        {
            emDGTD_param.electronDensityFileName = "";
        }

        //read ElectroMagneticSource
        if (tmp.HasMember("ElectroMagneticSource") && tmp["ElectroMagneticSource"].IsArray())
        {
            const rapidjson::Value& arr = tmp["ElectroMagneticSource"];
            emDGTD_param.electroMagneticSourceParameterList.resize(arr.Size());
            for (int i = 0; i < arr.Size(); ++i)
            {
                auto& electroMagneticSourceParameter = emDGTD_param.electroMagneticSourceParameterList[i];

                const rapidjson::Value& tmp1 = arr[i];

                if (!get_class_string(tmp1, electroMagneticSourceParameter.sourceType, "sourceType"))
                {

                }

                if (!get_class_string(tmp1, electroMagneticSourceParameter.boundaryName, "boundaryName"))
                {

                }

                if (!get_class_double_vector(tmp1, electroMagneticSourceParameter.waveInitialPosition, "waveInitialPosition"))
                {

                }

                if (!get_class_double_vector(tmp1, electroMagneticSourceParameter.totalFieldRegionCenterPosition, "totalFieldRegionCenterPosition"))
                {

                }

                if (!get_class_double_vector(tmp1, electroMagneticSourceParameter.totalFieldRegionSize, "totalFieldRegionSize"))
                {

                }

                if (!get_class_double(tmp1, electroMagneticSourceParameter.electricFieldAmplitude, "electricFieldAmplitude"))
                {

                }

                if (!get_class_double(tmp1, electroMagneticSourceParameter.angleTheta, "angleTheta"))
                {

                }

                if (!get_class_double(tmp1, electroMagneticSourceParameter.anglePhi, "anglePhi"))
                {

                }

                if (!get_class_double(tmp1, electroMagneticSourceParameter.polarizationAngleAlpha, "polarizationAngleAlpha"))
                {

                }

                if (!get_class_string(tmp1, electroMagneticSourceParameter.pulseType, "pulseType"))
                {

                }

                if (!get_class_double(tmp1, electroMagneticSourceParameter.gaussianPulseTimeWidth, "gaussianPulseTimeWidth"))
                {

                }

                if (!get_class_double(tmp1, electroMagneticSourceParameter.sinPulseFrequency, "sinPulseFrequency"))
                {

                }

                if (!get_class_double(tmp1, electroMagneticSourceParameter.plasmaInnerRadius, "plasmaInnerRadius"))
                {

                }

                if (!get_class_double(tmp1, electroMagneticSourceParameter.plasmaThickness, "plasmaThickness"))
                {

                }


            }
        }


        //read ElectroMagneticBoundaryConditionParameter
        if (tmp.HasMember("ElectroMagneticBoundaryCondition") && tmp["ElectroMagneticBoundaryCondition"].IsArray())
        {
            const rapidjson::Value& arr = tmp["ElectroMagneticBoundaryCondition"];
            emDGTD_param.electroMagneticBoundaryConditionParameterList.resize(arr.Size());
            for (int i = 0; i < arr.Size(); ++i)
            {
                auto& electroMagneticBoundaryConditionParameter = emDGTD_param.electroMagneticBoundaryConditionParameterList[i];

                const rapidjson::Value& tmp1 = arr[i];

                if (!get_class_string(tmp1, electroMagneticBoundaryConditionParameter.boundaryName, "boundaryName"))
                {

                }

                if (!get_class_string(tmp1, electroMagneticBoundaryConditionParameter.boundaryConditionType, "boundaryConditionType"))
                {

                }
            }
        }


        if (tmp.HasMember("RcsParameter"))
        {
            const rapidjson::Value& val = tmp["RcsParameter"];


            if (!get_class_string(val, emDGTD_param.rcsParameter.rcsType, "rcsType"))
            {
                emDGTD_param.rcsParameter.rcsType = "bistatic";
            }

            if (!get_class_double(val, emDGTD_param.rcsParameter.farFieldRadius, "farFieldRadius"))
            {
                emDGTD_param.rcsParameter.farFieldRadius = 100.0;
            }

            if (!get_class_double(val, emDGTD_param.rcsParameter.angleTheta, "angleTheta"))
            {
                emDGTD_param.rcsParameter.angleTheta = 180.0;
            }

            if (!get_class_double(val, emDGTD_param.rcsParameter.anglePhi, "anglePhi"))
            {
                emDGTD_param.rcsParameter.anglePhi = 180.0;
            }

            if (!get_class_double(val, emDGTD_param.rcsParameter.gaussianFrequencyMax, "gaussianFrequencyMax"))
            {
                emDGTD_param.rcsParameter.gaussianFrequencyMax = 10.0e9;
            }

            if (!get_class_int(val, emDGTD_param.rcsParameter.gaussianFrequencyNumber, "gaussianFrequencyNumber"))
            {
                emDGTD_param.rcsParameter.gaussianFrequencyNumber = 240;
            }
        }
        else
        {
            emDGTD_param.rcsParameter.rcsType = "bistatic";
            emDGTD_param.rcsParameter.farFieldRadius = 100.0;
            emDGTD_param.rcsParameter.anglePhi = 180.0;
            emDGTD_param.rcsParameter.gaussianFrequencyMax = 10.0e9;
            emDGTD_param.rcsParameter.gaussianFrequencyNumber = 240;
        }
    }
}


void Config::readMaterialDatabase()
{
    //=============read material database=======================================================
    std::string materialDataBaseName = dataBaseDir + "/material.database";
    //std::cout <<"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000===" << materialDataBaseName << endl;
    std::ifstream in(materialDataBaseName.c_str());
    if (!in.is_open())
    {
        log_warning << "fail to read input file: " << materialDataBaseName;
        return;
    }

    std::string json_content((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
    in.close();

    rapidjson::Document materialDom;
    if (materialDom.Parse(json_content.c_str()).HasParseError())
    {
        log_error << "params reactionDom error at offset " << materialDom.GetErrorOffset() << ": " << GetParseError_En(materialDom.GetParseError());
    }

    if (materialDom.IsArray())
    {
        for (auto iter = mesh_param.physicalGroupToMaterialMap.begin(); iter != mesh_param.physicalGroupToMaterialMap.end(); iter++)
        {
            auto& materialName = iter->second;
            std::string materialNameTemp = "";
            for (int iMaterial = 0; iMaterial < materialDom.Size(); iMaterial++)
            {
                const rapidjson::Value& tmp = materialDom[iMaterial];
                if (get_class_string(tmp, materialNameTemp, "name"))
                {
                    Material material;
                    material.name = materialNameTemp;
                    get_class_string(tmp, material.kind, "kind");
                    get_class_double(tmp, material.resistance, "resistance");
                    get_class_double(tmp, material.heatCapacity, "heat capacity");
                    get_class_double(tmp, material.conductivity, "conductivity");
                    get_class_double(tmp, material.relativePermittivity, "relative permittivity");
                    get_class_double(tmp, material.thermalConductivity, "thermal conductivity");

                    materialMap[material.name] = material;
                }
                else
                {
                    continue;
                }
            }
            if (materialNameTemp == "")
            {
                log_error << "no such material in database: " << materialName;
            }
        }

    }
    else
    {
        log_error << "materialDom is not json array";
        exit(0);
    }
    //=============end read material database=======================================================
}


void Config::readRecord()
{
    if (dom.HasMember("Record") && dom["Record"].IsArray())
    {
        const rapidjson::Value& arr = dom["Record"];
        record_param.resize(arr.Size());
        for (int i = 0; i < arr.Size(); ++i)
        {
            const rapidjson::Value& tmp = arr[i];


            if (!get_class_string(tmp, record_param[i].recordType, "recordType"))
            {
                log_error << "not found record type";
                exit(0);
            }

            if (!get_class_string(tmp, record_param[i].recordName, "recordName"))
            {
                if (record_param[i].recordType == "fieldAtMonitorPoint")
                {
                    log_error << "not found record name";
                    exit(0);
                }

            }

            if (!get_class_double_vector(tmp, record_param[i].monitorPointPosition, "monitorPointPosition"))
            {
                if (record_param[i].recordType == "fieldAtMonitorPoint")
                {
                    log_error << "not found monitorPointPosition";
                    exit(0);
                }

            }

            if (!get_class_string(tmp, record_param[i].faceGroupName, "faceGroupName"))
            {
                if (record_param[i].recordType == "electricPropulsion")
                {
                    log_error << "not found faceGroupName for electricPropulsion";
                    exit(0);
                }

            }
        }
    }



}


void Config::readLicense()
{
    
    if (dom.HasMember("License"))
    {
        const rapidjson::Value& tmp = dom["License"];

        if (!get_class_string(tmp, license_param.licenseVersion, "licenseVersion"))
        {
            log_error << "there is no licenseVersion";
            exit(0);
        }
        else
        {
            if (license_param.licenseVersion == "singleMachine" || license_param.licenseVersion == "network")
            {

            }
            else
            {
                log_fatal << "not support such license: " << license_param.licenseVersion;
                exit(0);
            }
        }

        //if (license_param.licenseVersion == "network")
        //{
        //    if (!get_class_string(tmp, license_param.serverIp, "serverIp"))
        //    {
        //        log_error << "there is no serverIp";
        //        exit(0);
        //    }

        //    if (!get_class_string(tmp, license_param.serverPort, "serverPort"))
        //    {
        //        log_error << "there is no serverPort";
        //        exit(0);
        //    }
        //}


        
        if (debugLevel > 0) log_info << "--------- end: material info";
    }
    else
    {
        log_error << "there is no license";
        exit(0);
    }
}


void Config::add_simulation_time(SimulationTime* sim_time_)
{
    sim_time = sim_time_;
}

void Config::addParallelMPI(ParallelMPI* pmpiInp)
{
    pmpi = pmpiInp;
}

void Config::compute()
{
    

}


bool Config::get_string(std::string& cpp_value, std::string value_name)
{
    if(dom.HasMember(value_name.c_str()) && dom[value_name.c_str()].IsString())
    {
        cpp_value = dom[value_name.c_str()].GetString();
        return true;
    }
    return false;
}

bool Config::get_double(double& cpp_value, std::string value_name)
{
    if(dom.HasMember(value_name.c_str()) && dom[value_name.c_str()].IsNumber())
    {
        cpp_value = dom[value_name.c_str()].GetDouble();
        return true;
    }
    return false;
}


bool Config::get_int(int& cpp_value, std::string value_name)
{
    if(dom.HasMember(value_name.c_str()) && dom[value_name.c_str()].IsInt())
    {
        cpp_value = dom[value_name.c_str()].GetInt();
        return true;
    }
    return false;
}

bool Config::get_bool(bool& cpp_value, std::string value_name)
{
    if(dom.HasMember(value_name.c_str()) && dom[value_name.c_str()].IsBool())
    {
        cpp_value = dom[value_name.c_str()].GetBool();
        return true;
    }
    return false;
}

bool Config::get_string_vector(std::vector<std::string>& cpp_value, std::string value_name)
{
    if(dom.HasMember(value_name.c_str()) && dom[value_name.c_str()].IsArray())
    {
        cpp_value.resize(dom[value_name.c_str()].Size());
        for(int i = 0; i < cpp_value.size(); i++)
        {
            const rapidjson::Value& tmp = dom[value_name.c_str()][i];
            if(tmp.IsString())
            {
                cpp_value[i] = tmp.GetString();
            }
            else
            {
                return false;
            }

        }
        return true;
    }
    return false;
}


bool Config::get_double_vector(std::vector<double>& cpp_value, std::string value_name)
{
    if(dom.HasMember(value_name.c_str()) && dom[value_name.c_str()].IsArray())
    {
        cpp_value.resize(dom[value_name.c_str()].Size());
        for(int i = 0; i < cpp_value.size(); i++)
        {
            const rapidjson::Value& tmp = dom[value_name.c_str()][i];
            if(tmp.IsNumber())
            {
                cpp_value[i] = tmp.GetDouble();
            }
            else
            {
                return false;
            }

        }
        return true;
    }
    return false;
}


bool Config::get_int_vector(std::vector<int>& cpp_value, std::string value_name)
{
    if(dom.HasMember(value_name.c_str()) && dom[value_name.c_str()].IsArray())
    {
        cpp_value.resize(dom[value_name.c_str()].Size());
        for(int i = 0; i < cpp_value.size(); i++)
        {
            const rapidjson::Value& tmp = dom[value_name.c_str()][i];
            if(tmp.IsInt())
            {
                cpp_value[i] = tmp.GetInt();
            }
            else
            {
                return false;
            }

        }
        return true;
    }
    return false;
}


bool Config::get_class_string(const rapidjson::Value& json_value, std::string& cpp_value, std::string value_name)
{
    if(json_value.HasMember(value_name.c_str()) && json_value[value_name.c_str()].IsString())
    {
        cpp_value = json_value[value_name.c_str()].GetString();
        return true;
    }
    return false;
}


bool Config::get_class_double(const rapidjson::Value& json_value, double& cpp_value, std::string value_name)
{
    if(json_value.HasMember(value_name.c_str()) && json_value[value_name.c_str()].IsNumber())
    {
        cpp_value = json_value[value_name.c_str()].GetDouble();
        return true;
    }
    return false;
}


bool Config::get_class_int(const rapidjson::Value& json_value, int& cpp_value, std::string value_name)
{
    if(json_value.HasMember(value_name.c_str()) && json_value[value_name.c_str()].IsInt())
    {
        cpp_value = json_value[value_name.c_str()].GetInt();
        return true;
    }
    return false;
}

bool Config::get_class_bool(const rapidjson::Value& json_value, bool& cpp_value, std::string value_name)
{
    if(json_value.HasMember(value_name.c_str()) && json_value[value_name.c_str()].IsBool())
    {
        cpp_value = json_value[value_name.c_str()].GetBool();
        return true;
    }
    return false;
}

bool Config::get_class_string_vector(const rapidjson::Value& json_value, std::vector<std::string>& cpp_value, std::string value_name)
{
    if(json_value.HasMember(value_name.c_str()) && json_value[value_name.c_str()].IsArray())
    {
        cpp_value.resize(json_value[value_name.c_str()].Size());
        for(int i = 0; i < cpp_value.size(); i++)
        {
            const rapidjson::Value& tmp = json_value[value_name.c_str()][i];
            if(tmp.IsString())
            {
                cpp_value[i] = tmp.GetString();
            }
            else
            {
                return false;
            }

        }
        return true;
    }
    return false;
}


bool Config::get_class_double_vector(const rapidjson::Value& json_value, std::vector<double>& cpp_value, std::string value_name)
{
    if(json_value.HasMember(value_name.c_str()) && json_value[value_name.c_str()].IsArray())
    {
        cpp_value.resize(json_value[value_name.c_str()].Size());
        for(int i = 0; i < cpp_value.size(); i++)
        {
            const rapidjson::Value& tmp = json_value[value_name.c_str()][i];
            if(tmp.IsNumber())
            {
                cpp_value[i] = tmp.GetDouble();
            }
            else
            {
                return false;
            }

        }
        return true;
    }
    return false;
}


bool Config::get_class_int_vector(const rapidjson::Value& json_value, std::vector<int>& cpp_value, std::string value_name)
{
    if(json_value.HasMember(value_name.c_str()) && json_value[value_name.c_str()].IsArray())
    {
        cpp_value.resize(json_value[value_name.c_str()].Size());
        for(int i = 0; i < cpp_value.size(); i++)
        {
            const rapidjson::Value& tmp = json_value[value_name.c_str()][i];
            if(tmp.IsInt())
            {
                cpp_value[i] = tmp.GetInt();
            }
            else
            {
                return false;
            }

        }
        return true;
    }
    return false;
}



/*
FieldBoundaryConditionParameter::FieldBoundaryConditionParameter(FieldBoundaryConditionParameter& fieldBoundaryConditionParameter)
{

}
*/